import cv2 #导入库
import numpy as np
def detect_circle(image):
    # dst = cv2.bilateralFilter(image, 0, 150, 5)  #高斯双边模糊，不太好调节,霍夫噪声敏感，所以要先消除噪声
    # cv2.imshow("1",dst)
    dst = cv2.pyrMeanShiftFiltering(image,5,100)  #均值迁移，EPT边缘保留滤波,霍夫噪声敏感，所以要先消除噪声
    cv2.imshow("2", dst)
    #dst = cv2.GaussianBlur(image,(13,15),15) #使用高斯模糊，修改卷积核ksize也可以检测出来
    #cv2.imshow("3", dst)
    gray = cv2.cvtColor(dst,cv2.COLOR_BGR2GRAY)
    circles = cv2.HoughCircles(gray,cv2.HOUGH_GRADIENT,2,50,param1=60,param2=110,minRadius=0,maxRadius=0)
    circles = np.uint16(np.around(circles))#around对数据四舍五入，为整数
    for i in circles[0,:]:
        cv2.circle(image,(i[0],i[1]),i[2],(0,0,255),2)
        cv2.circle(image,(i[0],i[1]),2,(255,0,0),2)   #圆心

    cv2.imshow("detect_circle",image)

src = cv2.imread("./circle (2).png",1)  #读取图片
cv2.namedWindow("input image",cv2.WINDOW_AUTOSIZE)    #创建GUI窗口,形式为自适应
cv2.imshow("input image",src)    #通过名字将图像和窗口联系

detect_circle(src)

cv2.waitKey(0)   #等待用户操作，里面等待参数是毫秒，我们填写0，代表是永远，等待用户操作
cv2.destroyAllWindows()  #销毁所有窗口
'''
1.image:输入图像 (灰度图)
2.method:指定检测方法. 现在OpenCV中只有霍夫梯度法
3.dp: 指的是累加器的图像和原图像的比例，如果dp为1，则累加器的图像和原图具有相同的比例，如果dp为2，则累加器图像的长宽均只有原图的一半。`
解释一下：
  当dp为1后，那么累加器会在累加器图像[0,w],[0,h]上可能的圆心位置(a,b)进行投票,最后来计算是否达到阈值来判定是否为圆心。
  当dp为2后，那么累加器会在累加器图像[0,w/2],[0,h/2]上可能的圆心位置(a,b)进行投票,最后来计算是否达到阈值来判定是否为圆心。 
  显然，当dp为2后，由于累加器图像的缩小，之前在dp=1上投票的可疑的相邻4个圆心的坐标点，在dp=2的累加器图像上会投票四次(因为长宽只有一半)
  与之对应下面的(4,5,6,7,8)都需要调整，例如：minDist 需要扩大一些，param_2需要扩大差不多4倍，半径也需要调小一点
4.minDist :如果圆心之间的距离在这个范围内会被认为是同心圆
5.param_1 = 200: Canny边缘检测的高阈值
6.param_2 = 100: 要检测到一个圆，那么必须检测到多少个点在这个圆的圆周上，实际上就是累加器的阈值
7.min_radius = 0: 能检测到的最小圆半径, 默认为0.
8.max_radius = 0: 能检测到的最大圆半径, 默认为0
'''